package com.markerhub.controller;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.markerhub.common.lang.Result;
import com.markerhub.entity.SysUser;
import com.markerhub.service.SysUserService;
import com.markerhub.utils.JwtUtils;
import com.markerhub.security.UserDetailServiceImpl;
import io.jsonwebtoken.Claims;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 认证管理Controller
 */
@Api(tags = "认证管理")
@RestController
@RequestMapping("/api/auth")
public class AuthController extends BaseController{

    @Autowired
    JwtUtils jwtUtils;

    @Autowired
    UserDetailServiceImpl userDetailService;

    /**
     * 用户登录
     * @param loginForm 登录表单
     * @return 登录结果，包含token
     */
    @ApiOperation(value = "用户登录", notes = "根据用户名和密码进行登录验证")
    @PostMapping("/login")
    public Result login(@RequestBody LoginForm loginForm) {
        System.out.println("收到登录请求: " + loginForm.getUsername());
        
        // 1.验证用户名密码
        SysUser sysUser = sysUserService.getByUsername(loginForm.getUsername());
        if (sysUser == null) {
            System.out.println("用户不存在: " + loginForm.getUsername());
            return Result.fail("用户名或密码错误");
        }
        
        // 验证用户状态
        if (sysUser.getStatus() != 1) {
            System.out.println("用户已被禁用: " + loginForm.getUsername());
            return Result.fail("用户已被禁用");
        }
        
        // 验证密码
        if (!loginForm.getPassword().equals(sysUser.getPassword())) {
            System.out.println("密码不正确: " + loginForm.getUsername());
            return Result.fail("用户名或密码错误");
        }
        
        System.out.println("用户验证通过: " + sysUser.getUsername());
        
        // 更新最后登录时间
        sysUser.setLast_login(LocalDateTime.now());
        sysUserService.updateById(sysUser);
        System.out.println("更新用户最后登录时间成功");
        
        // 2.生成JWT token
        String token = jwtUtils.generateToken(sysUser.getUsername());
        System.out.println("生成的token: " + token);
        
        // 3.设置用户登录状态
        // 设置SecurityContext，方便后续获取用户信息
        UserDetails userDetails = userDetailService.loadUserByUsername(sysUser.getUsername());
        List<GrantedAuthority> authorities = userDetailService.getUserAuthority(sysUser.getId());
        UsernamePasswordAuthenticationToken authenticationToken = 
            new UsernamePasswordAuthenticationToken(userDetails, null, authorities);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        
        // 4.返回token，确保格式符合前端期望
        Map<String, Object> responseData = new HashMap<>();
        responseData.put("token", token);
        
        System.out.println("登录成功，返回token: " + token);
        return Result.succ(200, "登录成功", responseData);
    }

    /**
     * 用户登出
     * @return 登出结果
     */
    @ApiOperation(value = "用户退出登录", notes = "用户退出登录接口")
    @PostMapping("/logout")
    public Result logout() {
        System.out.println("========== 进入logout方法 ==========");
        
        // 1. 清除SecurityContext中的认证信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null) {
            String username = authentication.getName();
            System.out.println("清除用户" + username + "的认证信息");
        }
        
        SecurityContextHolder.clearContext();
        System.out.println("已清除SecurityContext");
        
        // 2. 清除可能的ThreadLocal中的用户信息
        // 确保不会有内存泄漏
        
        // 3. 返回成功响应
        // 前端会在收到此响应后清除本地存储的token
        System.out.println("退出登录成功，准备返回响应");
        return Result.succ(200, "退出成功", null);
    }

    @ApiOperation(value = "获取用户信息", notes = "获取当前登录用户的基本信息和权限")
    @GetMapping("/userInfo")
    public Result userInfo(HttpServletRequest request) {
        System.out.println("========== 进入userInfo方法 ==========");
        
        // 1. 首先尝试从SecurityContext获取认证信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        System.out.println("SecurityContext认证对象: " + (authentication != null ? authentication.getClass().getSimpleName() : "null"));
        
        String username = null;
        
        // 检查认证状态
        if (authentication != null) {
            System.out.println("认证状态: " + authentication.isAuthenticated());
            System.out.println("Principal类型: " + (authentication.getPrincipal() != null ? authentication.getPrincipal().getClass().getSimpleName() : "null"));
            
            // 如果有有效的认证信息，直接获取用户名
            if (authentication.isAuthenticated() && authentication.getPrincipal() instanceof UserDetails) {
                UserDetails userDetails = (UserDetails) authentication.getPrincipal();
                username = userDetails.getUsername();
                System.out.println("1. 从SecurityContext(UserDetails)获取用户名: " + username);
            } else if (authentication.isAuthenticated() && authentication.getPrincipal() instanceof String && !"anonymousUser".equals(authentication.getPrincipal())) {
                username = (String) authentication.getPrincipal();
                System.out.println("2. 从SecurityContext(String)获取用户名: " + username);
            } else {
                System.out.println("3. SecurityContext中没有有效的认证信息，需要从token获取");
            }
        }
        
        // 2. 如果SecurityContext中没有用户名，则从token获取
        if (StrUtil.isBlank(username)) {
            String token = null;
            
            // 2.1 直接从Authorization头获取token（前端使用的标准方式）
            String authHeader = request.getHeader("Authorization");
            System.out.println("从Authorization头获取的值: " + (StrUtil.isBlank(authHeader) ? "空" : authHeader));
            
            if (StrUtil.isNotBlank(authHeader)) {
                token = authHeader; // 保留完整的token，让JwtUtils内部处理Bearer前缀
                System.out.println("使用Authorization头作为token: " + (token.length() > 20 ? token.substring(0, 20) + "..." : token));
            }
            
            // 2.2 如果为空，尝试从自定义JWT头获取
            if (StrUtil.isBlank(token)) {
                String jwtHeader = jwtUtils.getHeader();
                System.out.println("使用的JWT头名称: " + jwtHeader);
                token = request.getHeader(jwtHeader);
                System.out.println("从JWT头获取的token: " + (StrUtil.isBlank(token) ? "空" : "非空"));
            }
            
            // 2.3 如果仍然为空，尝试从请求参数获取
            if (StrUtil.isBlank(token)) {
                token = request.getParameter("token");
                System.out.println("从请求参数获取的token: " + (StrUtil.isBlank(token) ? "空" : "非空"));
            }
            
            // 3. 从token中解析用户名
            if (StrUtil.isNotBlank(token)) {
                try {
                    System.out.println("开始解析token...");
                    Claims claims = jwtUtils.getClaimByToken(token);
                    
                    if (claims != null) {
                        System.out.println("token解析成功，包含claims");
                        
                        // 检查token是否过期
                        if (jwtUtils.isTokenExpired(claims)) {
                            System.out.println("token已过期");
                            return Result.fail("登录已过期，请重新登录");
                        }
                        
                        username = claims.getSubject();
                        System.out.println("从token中解析的用户名: " + username);
                    } else {
                        System.out.println("token解析失败，claims为null");
                    }
                } catch (Exception e) {
                    System.out.println("解析token异常: " + e.getMessage());
                    e.printStackTrace();
                }
            } else {
                System.out.println("未找到有效的token");
            }
        }
        
        // 4. 验证用户名是否存在
        if (StrUtil.isBlank(username)) {
            System.out.println("无法获取用户名，返回400错误");
            return Result.fail("未找到用户信息，请重新登录");
        }
        
        // 5. 获取用户信息
        System.out.println("根据用户名" + username + "查询用户信息...");
        SysUser sysUser = sysUserService.getByUsername(username);
        
        if (sysUser == null) {
            System.out.println("用户不存在: " + username);
            return Result.fail("用户不存在");
        }
        
        System.out.println("成功获取用户信息: ID=" + sysUser.getId() + ", 用户名=" + sysUser.getUsername());
        
        // 6. 获取权限信息
        List<GrantedAuthority> authorities = userDetailService.getUserAuthority(sysUser.getId());
        String[] authorityInfoArray = authorities.stream()
                .map(GrantedAuthority::getAuthority)
                .toArray(String[]::new);
        System.out.println("用户权限数量: " + authorityInfoArray.length);
        
        // 7. 构建用户信息对象，确保返回格式完全符合前端期望
        Map<String, Object> userData = new HashMap<>();
        userData.put("id", sysUser.getId());
        userData.put("username", sysUser.getUsername());
        userData.put("avatar", sysUser.getAvatar());
        userData.put("created", sysUser.getCreated());
        userData.put("authorities", authorityInfoArray);
        
        System.out.println("构建的用户数据: {id=" + sysUser.getId() + ", username=" + sysUser.getUsername() + "}");
        
        // 8. 返回结果
        // Result.succ会包装成{code, msg, data}格式
        // 前端axios拦截器处理后，在Home.vue中通过res.data.data访问
        System.out.println("返回用户信息成功");
         return Result.succ(200, "获取用户信息成功", userData);
     }

    /**
     * 登录表单内部类
     */
    public static class LoginForm {
        private String username;
        private String password;

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }
}
